#include "common/config/config.h"
#include "common/log/log.h"
#include "common/more/json.h"

#include "converter.h"

namespace F2FB
{

Elements::Workflows Converter::workflows(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::Workflows result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::Workflow>();
        element->setId(entity->value<unsigned>("id"));
        element->setCaption(entity->value<std::string>("caption"));
        element->setDescription(entity->value<std::string>("description"));
        result.push_back(element);
    }
    return result;
}

Elements::States Converter::states(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::States result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::State>();
        element->setId(entity->value<unsigned>("id"));
        element->setCaption(entity->value<std::string>("caption"));
        element->setDescription(entity->value<std::string>("description"));
        element->setWorkflowId(entity->value<unsigned>("workflow_id"));
        element->setWeight(entity->value<unsigned>("weight"));
        element->setOrderNumber(entity->value<unsigned>("order"));
        element->setIsArchive(entity->value<bool>("is_archive"));
        result.push_back(element);
    }
    return result;
}

Elements::Edges Converter::edges(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::Edges result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::Edge>();
        element->setId(entity->value<unsigned>("id"));
        element->setBeginStateId(entity->value<unsigned>("from_state_id"));
        element->setEndStateId(entity->value<unsigned>("to_state_id"));
        result.push_back(element);
    }
    return result;
}

Elements::ItemTypes Converter::itemTypes(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::ItemTypes result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::ItemType>();
        element->setId(entity->value<unsigned>("id"));
        element->setCaption(entity->value<std::string>("caption"));
        element->setWorkflowId(entity->value<unsigned>("workflow_id"));
        element->setDefaultStateId(entity->value<unsigned>("default_state_id"));
        element->setKind(Elements::ItemType::Kind::Issue);
        result.push_back(element);
    }
    return result;
}

Elements::FieldTypes Converter::fieldTypes(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::FieldTypes result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::FieldType>();
        element->setId(entity->value<unsigned>("id"));
        element->setItemTypeId(entity->value<unsigned>("issue_kind_id"));
        element->setCaption(entity->value<std::string>("caption"));
        element->setDescription(entity->value<std::string>("description"));
        element->setValueType(Elements::FieldType::ValueType(entity->value<unsigned>("value_type")));
        element->setIsBoardVisible(entity->value<bool>("is_system"));
        result.push_back(element);
    }
    return result;
}

Elements::Users Converter::users(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::Users result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::User>();
        element->setId(entity->value<unsigned>("id"));
        element->setLogin(entity->value<std::string>("login"));
        element->setFirstName(entity->value<std::string>("first_name"));
        element->setMiddleName(entity->value<std::string>("middle_name"));
        element->setLastName(entity->value<std::string>("last_name"));
        element->setEmail(entity->value<std::string>("email"));
        element->setPasswordHash(entity->value<std::string>("password_hash"));
        element->setNeedChangePassword(entity->value<bool>("need_change_password"));
        element->setIsBlocked(entity->value<bool>("is_blocked"));
        element->setUiLang("ru");
        result.push_back(element);
    }
    return result;
}

Elements::Projects Converter::projects(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::Projects result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::Project>();
        element->setId(entity->value<unsigned>("id"));
        element->setCaption(entity->value<std::string>("caption"));
        element->setDescription(entity->value<std::string>("content"));
        result.push_back(element);
    }
    return result;
}

Elements::Phases Converter::phases(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::Phases result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::Phase>();
        element->setId(entity->value<unsigned>("id"));
        element->setCaption(entity->value<std::string>("caption"));
        element->setDescription(entity->value<std::string>("content"));
        element->setProjectId(entity->value<unsigned>("project_id"));
        element->setBeginDate(entity->value<std::time_t>("start_date"));
        element->setEndDate(entity->value<std::time_t>("release_date"));
        result.push_back(element);
    }
    return result;
}

Elements::Items Converter::items(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::Items result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::Item>();
        element->setId(entity->value<unsigned>("id"));
        element->setItemTypeId(entity->value<unsigned>("issue_kind_id"));
        element->setParentId(entity->value<unsigned>("parent_id"));
        element->setStateId(entity->value<unsigned>("state_id"));
        element->setCaption(entity->value<std::string>("caption"));
        element->setDescription(entity->value<std::string>("content"));
        element->setPhaseId(entity->value<unsigned>("version_id"));
        result.push_back(element);
    }
    return result;
}

Elements::ItemHistories Converter::itemHistories(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::ItemHistories result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::ItemHistory>();
        element->setId(entity->value<unsigned>("id"));
        element->setItemId(entity->value<unsigned>("issue_id"));
        element->setDiff(entity->value<std::string>("diff"));
        element->setUserId(entity->value<unsigned>("user_id"));
        element->setTimestamp(entity->value<std::time_t>("date_time"));
        result.push_back(element);
    }
    return result;
}

Elements::ItemUserStates Converter::itemUserStates(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    auto newStateId = [](auto json)
    {
        const std::string value = json.value();
        if (value.empty())
            return 0;
        return bool("+" == value.substr(0, 1)) ? std::stoi(json.key()) : 0;
    };

    Elements::ItemUserStates result;
    for (const auto& entity : entities)
    {
        const auto diff = Common::stringToJson(entity->value<std::string>("diff"));
        if (!diff.contains("3"))
            continue;

        unsigned stateId = 0;
        for (const auto& stateDiff : diff["3"].items())
        {
            stateId = newStateId(stateDiff);
            if (0 != stateId)
                break;
        }
        if (0 == stateId)
            continue;

        auto element = std::make_shared<Elements::ItemUserState>();
        element->setId(entity->value<unsigned>("id"));
        element->setItemId(entity->value<unsigned>("issue_id"));
        element->setStateId(stateId);
        element->setUserId(entity->value<unsigned>("user_id"));
        element->setTimestamp(entity->value<std::time_t>("date_time"));
        result.push_back(element);
    }
    return result;
}

Elements::ItemFields Converter::itemFields(
    std::vector<std::shared_ptr<F2FB::Database::Entity>> entities
)
{
    Elements::ItemFields result;
    for (const auto& entity : entities)
    {
        auto element = std::make_shared<Elements::ItemField>();
        element->setId(entity->value<unsigned>("id"));
        element->setItemId(entity->value<unsigned>("issue_id"));
        element->setFieldTypeId(entity->value<unsigned>("field_kind_id"));
        element->setValue(entity->value<std::string>("value"));
        result.push_back(element);
    }
    return result;
}

} // namespace F2FB
